#include "hal_api.h"
#include "printf.h"

#define SPI0_CS_NO          0
#define LCD_A0_HIGH         Hal_Gpio_SetVal(GPIO_PORT_A, GPIO_04, GPIO_PIN_ACTIVE_HIGH)
#define LCD_A0_LOW          Hal_Gpio_SetVal(GPIO_PORT_A, GPIO_04, GPIO_PIN_ACTIVE_LOW)
//#define LCD_RST_HIGH        Hal_Gpio_SetVal(GPIO_PORT_A, GPIO_15, GPIO_PIN_ACTIVE_HIGH)
//#define LCD_RST_LOW         Hal_Gpio_SetVal(GPIO_PORT_A, GPIO_15, GPIO_PIN_ACTIVE_LOW)

#define CHAR_ASCII_OFFSET   32

#define CMD_DISPLAY_ON      0xAF
#define CMD_DISPLAY_OFF     0xAE
#define CMD_POWER_ON        0x2F
#define CMD_SET_EV          0x81
#define CMD_SET_RATIO       0x24
#define CMD_SET_PAGE        0xB0
#define CMD_SET_BAIS        0xA2
#define CMD_SEG_DIR         0xA0
#define CMD_SET_PAGE_ADDR   0xB0
#define CMD_SCAN_MODE       0xC2
#define CMD_SET_COLUM_MSB   0x10
#define CMD_SET_COLUM_LSB   0x00

#define LCD_PAGE_NUMS       9
#define LCD_COLUM_NUMS      132


static const uint8_t char_8x16[]=
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//   0
	0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//!  1
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0C,0x10,0x06,0x0C,0x01,0x00,//"  2
	0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//#  3
	0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$  4
	0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//%  5
	0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//&  6
	0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//'  7
	0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//(  8
	0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//)  9
	0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//*  10
	0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+  11
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//,  12
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//-  13
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//.  14
	0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,//"/"  15
	0x00,0x03,0x1F,0x10,0x20,0x10,0x1C,0x07,0x00,0xE0,0xF8,0x04,0x04,0x04,0x38,0xF0,//"0"  16
	0x00,0x00,0x00,0x08,0x1F,0x1F,0x00,0x00,0x00,0x00,0x04,0x04,0xFC,0xFC,0x00,0x00,//"1"  17
	0x00,0x0C,0x14,0x10,0x20,0x21,0x1B,0x0E,0x00,0x18,0x70,0x48,0x8C,0x8C,0x0C,0x18,//"2", 18
	0x00,0x0C,0x14,0x10,0x20,0x21,0x1F,0x0C,0x00,0x10,0x28,0x04,0x04,0x04,0x8C,0x78,//"3", 19
	0x00,0x00,0x00,0x03,0x04,0x1F,0x00,0x00,0x00,0x60,0xA0,0x20,0x24,0xFC,0x24,0x00,//"4", 20
	0x00,0x03,0x1D,0x32,0x32,0x32,0x31,0x00,0x00,0x10,0x28,0x04,0x04,0x04,0x98,0xF0,//"5", 21
	0x00,0x03,0x0F,0x11,0x11,0x21,0x1D,0x08,0x00,0xF0,0xF8,0x04,0x04,0x04,0x98,0xF0,//"6", 22
	0x00,0x1C,0x10,0x30,0x10,0x09,0x0B,0x3C,0x00,0x00,0x00,0x00,0x78,0xC0,0x00,0x00,//"7", 23
	0x00,0x00,0x1E,0x11,0x21,0x21,0x1F,0x0C,0x00,0x70,0xF8,0x04,0x04,0x04,0x8C,0xF8,//"8", 24
	0x00,0x07,0x1F,0x10,0x20,0x10,0x19,0x0F,0x00,0x00,0x98,0x44,0x44,0x4C,0xB8,0xE0,//"9", 25
	0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//:  26
	0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//;  27
	0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//<  28
	0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//=  29
	0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//>  30
	0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//?  31
	0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@  32

	0x00,0x00,0x00,0x07,0x1C,0x0F,0x00,0x00,0x04,0x04,0x7C,0xA0,0x20,0xA4,0xFC,0x08,//"A"  33
	0x00,0x20,0x3F,0x21,0x21,0x21,0x11,0x1B,0x00,0x00,0xFC,0x04,0x04,0x04,0x84,0xCC,//"B"  34
	0x00,0x03,0x0F,0x10,0x10,0x20,0x10,0x1C,0x00,0xE0,0xF8,0x0C,0x04,0x04,0x04,0x18,//"C"  35
	0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0E,0x00,0x00,0xFC,0x04,0x04,0x04,0x0C,0x38,//"D"  36
	0x00,0x20,0x3F,0x21,0x21,0x27,0x20,0x3C,0x00,0x04,0xFC,0x04,0x04,0x84,0x04,0x1C,//"E"  37
	0x00,0x20,0x3F,0x21,0x21,0x27,0x20,0x3C,0x00,0x04,0xFC,0x04,0x00,0x80,0x00,0x00,//"F"  38
	0x00,0x03,0x0F,0x10,0x10,0x20,0x10,0x1C,0x00,0xE0,0xF8,0x0C,0x04,0x04,0x44,0x78,//"G"  39
	0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x21,0x00,0x04,0xFC,0x04,0x00,0x00,0x04,0x04,//"H"  40
	0x00,0x20,0x3F,0x20,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0x04,0x00,0x00,0x00,0x00,//"I"  41
	0x00,0x00,0x00,0x20,0x3F,0x00,0x00,0x00,0x00,0x38,0x04,0x0C,0xF8,0x00,0x00,0x00,//"J"  42
	0x00,0x20,0x3F,0x20,0x01,0x03,0x04,0x28,0x00,0x04,0xFC,0x84,0x00,0xC0,0x74,0x1C,//"K"  43
	0x00,0x20,0x3F,0x20,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0x04,0x04,0x04,0x04,0x3C,//"L"  44
	0x00,0x20,0x3F,0x1F,0x01,0x00,0x00,0x07,0x00,0x04,0xFC,0x00,0xF0,0x28,0xF0,0x04,//"M"  45
	0x00,0x20,0x3F,0x1C,0x07,0x01,0x00,0x20,0x00,0x04,0xFC,0x00,0x00,0xC0,0x70,0x18,//"N"  46
	0x00,0x03,0x0F,0x10,0x10,0x20,0x10,0x0E,0x00,0xC0,0xF8,0x0C,0x04,0x04,0x0C,0x78,//"O"  47
	0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x19,0x00,0x04,0xFC,0x84,0x80,0x80,0x80,0x80,//"P"  48
	0x00,0x03,0x0F,0x10,0x10,0x20,0x10,0x0E,0x00,0xC0,0xF8,0x1C,0x24,0x24,0x1F,0x79,//"Q"  49
	0x00,0x20,0x3F,0x21,0x21,0x21,0x11,0x1B,0x00,0x04,0xFC,0x04,0x00,0x80,0x70,0x1C,//"R"  50
	0x00,0x0C,0x12,0x11,0x21,0x11,0x10,0x3C,0x00,0x3C,0x08,0x04,0x04,0x84,0x84,0x78,//"S"  51
	0x00,0x3C,0x20,0x20,0x3F,0x20,0x20,0x3C,0x00,0x00,0x04,0x04,0xFC,0x00,0x00,0x00,//"T"  52
	0x00,0x20,0x3F,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0xF0,0x18,0x04,0x04,0x04,0x08,//"U"  53
	0x00,0x30,0x3E,0x03,0x00,0x00,0x27,0x38,0x00,0x00,0x00,0xE0,0x38,0x70,0x80,0x00,//"V"  54
	0x00,0x20,0x3F,0x23,0x03,0x3C,0x1F,0x00,0x00,0x00,0x00,0xF8,0xF0,0x00,0xF0,0xF8,//"W"  55
	0x00,0x20,0x38,0x06,0x01,0x03,0x2C,0x30,0x04,0x04,0x1C,0x60,0x80,0x64,0x1C,0x00,//"X"  56
	0x00,0x20,0x38,0x06,0x03,0x01,0x26,0x38,0x00,0x00,0x00,0x04,0xFC,0xFC,0x00,0x00,//"Y"  57
	0x00,0x1C,0x30,0x20,0x21,0x27,0x3C,0x30,0x00,0x04,0x1C,0x74,0xC4,0x04,0x04,0x3C,//"Z"  58

	0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[  59
	0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\  60
	0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//]  61
	0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^  62
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_  63
	0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//`  64
	0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00,0x38,0x7C,0x44,0x44,0x48,0xF8,0x00,//"a"  65
	0x00,0x20,0x3F,0x01,0x02,0x02,0x03,0x01,0x00,0x00,0xF8,0x08,0x04,0x04,0x0C,0xF8,//"b"  66
	0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00,0xF0,0xF8,0x04,0x04,0x04,0x88,0x80,//"c"  67
	0x00,0x00,0x01,0x02,0x02,0x22,0x3F,0x1F,0x00,0xF0,0xF8,0x04,0x04,0x04,0xFC,0xFC,//"d"  68
	0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00,0xF0,0xF8,0x44,0x44,0x44,0xC8,0xC0,//"e"  69
	0x00,0x02,0x1F,0x12,0x38,0x00,0x00,0x00,0x00,0x04,0xFC,0x04,0x00,0x00,0x00,0x00,//"f"  70
	0x00,0x00,0x01,0x02,0x02,0x03,0x02,0x02,0x00,0x1B,0xE5,0x15,0x15,0xE5,0xC7,0x01,//"g"  71
	0x00,0x20,0x3F,0x01,0x02,0x02,0x03,0x01,0x00,0x04,0xFC,0x04,0x00,0x04,0x04,0xFC,//"h"  72
	0x00,0x02,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0x04,0x00,0x00,0x00,0x00,//"i"  73
	0x00,0x02,0x13,0x13,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0x00,0x00,0x00,0x00,//"j"  74
	0x00,0x20,0x3F,0x00,0x00,0x02,0x03,0x02,0x00,0x04,0xFC,0x24,0x40,0xF4,0x1C,0x04,//"k"  75
	0x00,0x20,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0x04,0x00,0x00,0x00,0x00,//"l"  76
	0x00,0x02,0x03,0x01,0x02,0x02,0x03,0x01,0x00,0x04,0xFC,0x04,0x00,0x04,0x04,0xFC,//"m"  77
	0x00,0x02,0x03,0x01,0x02,0x02,0x03,0x01,0x00,0x04,0xFC,0x04,0x00,0x04,0x04,0xFC,//"n"  78
	0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00,0xF0,0xF8,0x04,0x04,0x04,0x98,0xF0,//"o"  79
	0x00,0x02,0x03,0x01,0x02,0x02,0x03,0x01,0x00,0x01,0xFF,0x09,0x04,0x04,0x0C,0xF8,//"p"  80
	0x00,0x00,0x01,0x02,0x02,0x02,0x03,0x03,0x00,0xF0,0xF8,0x04,0x04,0x05,0xFF,0xFF,//"q"  81
	0x00,0x02,0x03,0x01,0x02,0x03,0x03,0x00,0x00,0x04,0xFC,0x84,0x00,0x00,0x00,0x00,//"r"  82
	0x00,0x01,0x02,0x02,0x02,0x03,0x03,0x00,0x00,0x9C,0xC8,0x44,0x64,0x24,0x98,0x00,//"s"  83
	0x00,0x02,0x1F,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x0C,0x04,0x08,0x00,0x00,//"t"  84
	0x00,0x02,0x03,0x00,0x00,0x02,0x02,0x03,0x00,0x00,0xF8,0x0C,0x04,0x04,0x08,0xFC,//"u"  85
	0x02,0x02,0x03,0x00,0x00,0x02,0x03,0x00,0x00,0x00,0xC0,0x78,0x18,0x60,0x80,0x00,//"v"  86
	0x02,0x02,0x03,0x00,0x00,0x03,0x01,0x02,0x00,0x00,0xC0,0xF8,0x78,0x80,0xF8,0x38,//"w"  87
	0x00,0x02,0x03,0x01,0x00,0x02,0x03,0x02,0x00,0x04,0x0C,0x90,0x60,0xF4,0x0C,0x00,//"x"  88
	0x00,0x02,0x03,0x00,0x00,0x02,0x03,0x02,0x00,0x01,0x81,0xF1,0x1E,0x38,0xC0,0x00,//"y"  89
	0x00,0x03,0x02,0x02,0x02,0x03,0x03,0x00,0x00,0x84,0x0C,0x34,0x64,0x84,0x1C,0x00,//"z"  90
	0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{  91
	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//|  92
	0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//}  93
	0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~  94
};


static void lcd_write_char_cmd(Spi_Cfg_t_Ptr spi_ptr, uint8_t cmd)
{
	LCD_A0_LOW;
	Hal_Cnt_DelayMs(10);
	Hal_Spi_Transfer(spi_ptr, &cmd, 1, NULL, 0);
}

static void lcd_write_char_data(Spi_Cfg_t_Ptr spi_ptr, uint8_t data)
{
	LCD_A0_HIGH;
	Hal_Cnt_DelayMs(10);
	Hal_Spi_Transfer(spi_ptr, &data, 1, NULL, 0);
}

void lcd_clear(Spi_Cfg_t_Ptr spi_ptr)
{
	uint8_t x, y;
	for (y = 0; y < LCD_PAGE_NUMS; y++) {
		lcd_write_char_cmd(spi_ptr, CMD_SET_PAGE_ADDR + y);
		lcd_write_char_cmd(spi_ptr, CMD_SET_COLUM_MSB);
		lcd_write_char_cmd(spi_ptr, CMD_SET_COLUM_LSB);
		for (x = 0; x < LCD_COLUM_NUMS; x++) {
			lcd_write_char_data(spi_ptr, 0xFF);
		}
	}
}

static void lcd_set_pos(Spi_Cfg_t_Ptr spi_ptr, uint8_t page, uint8_t colum)
{
	page &= 0x0F;
	lcd_write_char_cmd(spi_ptr, page | CMD_SET_PAGE_ADDR);
	lcd_write_char_cmd(spi_ptr, (colum & 0x0F) | CMD_SET_COLUM_LSB);
	colum = (colum >> 4) & 0x0F;
	colum |= CMD_SET_COLUM_MSB;
	lcd_write_char_cmd(spi_ptr, colum);
}

void lcd_display_char(Spi_Cfg_t_Ptr spi_ptr, uint8_t page, uint8_t colum, uint8_t chr)
{
	uint8_t i;
	uint8_t data;
	if (chr < CHAR_ASCII_OFFSET) {
		return;
	}
	lcd_set_pos(spi_ptr, page, colum);
	for (i = 0; i < 8; i++) {
		data = ~char_8x16[(chr - CHAR_ASCII_OFFSET) * 16 + i + 8];
		lcd_write_char_data(spi_ptr, data);
	}
	lcd_set_pos(spi_ptr, page + 1, colum);
	for (i = 0; i < 8; i++) {
		data = ~char_8x16[(chr - CHAR_ASCII_OFFSET)* 16 + i];
		lcd_write_char_data(spi_ptr, data);
	}
}



void lcd_init(Spi_Cfg_t_Ptr spi_ptr)
{
	//lcd rst ctrl by hardware when power on
	//LCD_RST_LOW;
	//Hal_Cnt_DelayMs(10);
	//LCD_RST_HIGH;
	//Hal_Cnt_DelayMs(100);

	lcd_write_char_cmd(spi_ptr, CMD_SET_BAIS);
	lcd_write_char_cmd(spi_ptr, CMD_SEG_DIR);
	lcd_write_char_cmd(spi_ptr, CMD_SCAN_MODE);
	lcd_write_char_cmd(spi_ptr, CMD_SET_RATIO);
	lcd_write_char_cmd(spi_ptr, CMD_SET_EV);
	lcd_write_char_cmd(spi_ptr, CMD_POWER_ON);
	lcd_write_char_cmd(spi_ptr, CMD_SET_PAGE);
	lcd_write_char_cmd(spi_ptr, CMD_DISPLAY_ON);
}

int32_t test_spi0_lcd(void)
{
	Spi_Cfg_t lcd_spi = {SPI_ID_0, SPI0_CS_NO};

	printf("\r\n[SPI0 LCD]: TEST START\r\n");


	lcd_init(&lcd_spi);
	//clear disyplay ram takes long time
	lcd_clear(&lcd_spi);

	lcd_display_char(&lcd_spi, 0, 0, '1');
	lcd_display_char(&lcd_spi, 0, 8, '2');
	lcd_display_char(&lcd_spi, 0, 16, '3');
	lcd_display_char(&lcd_spi, 0, 24, '4');
	lcd_display_char(&lcd_spi, 0, 32, '5');
	lcd_display_char(&lcd_spi, 0, 40, '6');
	lcd_display_char(&lcd_spi, 0, 48, '7');
	lcd_display_char(&lcd_spi, 0, 56, '8');
	lcd_display_char(&lcd_spi, 0, 64, '9');

	lcd_display_char(&lcd_spi, 2, 0, '1');
	lcd_display_char(&lcd_spi, 2, 8, '2');
	lcd_display_char(&lcd_spi, 2, 16, '3');
	lcd_display_char(&lcd_spi, 2, 24, '4');
	lcd_display_char(&lcd_spi, 2, 32, '5');
	lcd_display_char(&lcd_spi, 2, 40, '6');
	lcd_display_char(&lcd_spi, 2, 48, '7');
	lcd_display_char(&lcd_spi, 2, 56, '8');
	lcd_display_char(&lcd_spi, 2, 64, '9');
	printf("\r\n[SPI0 LCD]: TEST END\r\n");

	return 0;
}

